﻿using Fleck;


namespace CabinetGrid.DeviceDriver.IModules.Impls
{
    public partial class WebSocketModule : IModule
    {
        private readonly ILogger _logger;
        private readonly ViewModel _viewModel;
        private readonly WebSocketServer _server;

        public WebSocketModule( ILoggerFactory loggerFactory, ViewModel viewModel )
        {
            _logger = loggerFactory.CreateLogger( nameof( WebSocketModule ) );
            _viewModel = viewModel;

            FleckLog.LogAction = ( level, message, ex ) =>
            {
                switch ( level )
                {
                    case Fleck.LogLevel.Warn: ConsoleWirter.Warning( $"+ [ws] {message}" ); break;
                    case Fleck.LogLevel.Error: ConsoleWirter.Error( $"+ [ws] {message}" ); break;
                    case Fleck.LogLevel.Debug: break;
                    case Fleck.LogLevel.Info:
                    default: ConsoleWirter.Debug( $"+ [ws]: {message}" ); break;
                }
            };

            _server = new WebSocketServer( _viewModel.AppConfig.TcpServer.WebSocket );
            _server.RestartAfterListenError = true;
        }

        public async Task StartAsync( CancellationToken cancellationToken )
        {
            _server.Start( socket =>
            {
                socket.OnOpen = ( ) =>
                {
                    _logger.Debug( $"ws client connected: {socket.ConnectionInfo.ClientIpAddress}:{socket.ConnectionInfo.ClientPort}, id: {socket.ConnectionInfo.Id}" );

                    _viewModel.WebSocketClientList.RemoveAll( i => i.ConnectionInfo.ClientIpAddress == socket.ConnectionInfo.ClientIpAddress );
                    _viewModel.WebSocketClientList.Add( socket );
                };

                socket.OnClose = ( ) =>
                {
                    _logger.Debug( $"ws client disconnected: {socket.ConnectionInfo.ClientIpAddress}:{socket.ConnectionInfo.ClientPort}, id: {socket.ConnectionInfo.Id}" );

                    _viewModel.WebSocketClientList.Remove( socket );
                };

                socket.OnMessage = data =>
                {
                    _logger.Debug( $"ws 接收客户端消息: {data}" );

                    Dtos.MsgDto msg = null;

                    try
                    {
                        msg = JsonConvert.DeserializeObject<Dtos.MsgDto>( data );
                        if ( msg.Data is null ) msg.Data = new Dictionary<string, object>( );

                        switch ( msg.Cmd.ToLower( ) )
                        {
                            #region ======RFID UHF======
                            case "rfid_uhf_check":
                                {
                                    msg.Data["check"] = _viewModel.RFIDUHFReaderList.All( i => i.ReaderState != Dev.Integration.UHFReader.Constants.ReaderState.Close );
                                    break;
                                }
                            case "rfid_uhf_scan":
                                {
                                    msg.Data.TryGetValue( "reader", out string reader );
                                    msg.Data.TryGetValue( "ants", out string ants );
                                    msg.Data.TryGetValue( "count", out string count );
                                    msg.Data.TryGetValue( "include_tid", out bool includeTID );

                                    var tagList = _viewModel.RFIDUHFInventoryScan( reader, ants.ToEnumerableOrDefault<byte>( ',' ).ToArray( ), count.ToIntOrDefault( defaultValue: 1 ), includeTID );
                                    msg.Data["count"] = tagList.Count( );
                                    msg.Data["list"] = tagList;
                                    break;
                                }
                            case "rfid_uhf_locate":
                                {
                                    msg.Data.GetValueIfNullThrowException( "reader", out string reader );
                                    msg.Data.GetValueIfNullThrowException( "ants", out string ants );
                                    msg.Data.GetValueIfNullThrowException( "epc", out string epc );
                                    msg.Data.TryGetValue( "duration", out string duration );    // 单位: ms

                                    var success = _viewModel.RFIDUHFLocate( reader, ants.ToEnumerableOrDefault<byte>( ',' ).ToList( ), epc, duration.ToIntOrDefault( defaultValue: 1000 ) );
                                    msg.Data["success"] = success;
                                    break;
                                }
                            #endregion


                            #region ======RFID HF======
                            case "rfid_hf_check":
                                {
                                    msg.Data["check"] = _viewModel.RFIDHFReaderList.All( i => i.ReaderState != Dev.Integration.HFReader.Constants.ReaderState.Close );
                                    break;
                                }
                            case "rfid_hf_scan":
                                {
                                    msg.Data.TryGetValue( "reader", out string reader );
                                    msg.Data.TryGetValue( "ants", out string ants );
                                    msg.Data.TryGetValue( "count", out string count );
                                    msg.Data.TryGetValue( "read_block", out bool readBlock );
                                    msg.Data.TryGetValue( "block_start", out string blockStartIndex );
                                    msg.Data.TryGetValue( "block_count", out string blockCount );

                                    var tagList = _viewModel.RFIDHFInventoryScan( reader
                                                                                , ants.ToEnumerableOrDefault<byte>( ',' ).ToArray( )
                                                                                , count.ToIntOrDefault( defaultValue: 1 )
                                                                                , readBlock
                                                                                , blockStartIndex.ToIntOrDefault( defaultValue: 0 )
                                                                                , blockCount.ToIntOrDefault( defaultValue: 1 ) );

                                    msg.Data["count"] = tagList.Count( );
                                    msg.Data["list"] = tagList;
                                    break;
                                }
                            #endregion


                            #region ======Locker======
                            case "locker_check":
                                {
                                    msg.Data["check"] = _viewModel.Locker?.IsOpened ?? false;
                                    break;
                                }
                            case "locker_open":
                                {
                                    msg.Data.TryGetValue( "addr", out string addr );
                                    msg.Data.TryGetValue( "no", out string no );

                                    var success = _viewModel.Locker.Unlock( addr.ToByteOrDefault( defaultValue: 1 ), no.ToByteOrDefault( defaultValue: 1 ) );
                                    msg.Data["success"] = success;
                                    break;
                                }
                            case "locker_query":
                                {
                                    msg.Data.TryGetValue( "addr", out string addr );

                                    var list = _viewModel.Locker.QueryState( addr.ToByteOrDefault( defaultValue: 1 ) );
                                    msg.Data["count"] = list.Count;
                                    msg.Data["list"] = list.Select( i => new
                                    {
                                        addr = i.Addr,
                                        no = i.No,
                                        state = (int)i.State,
                                    } );
                                    break;
                                }
                            #endregion


                            #region ======Card Reader======
                            case "card_reader_check":
                                {
                                    msg.Data["check"] = _viewModel.CardReader.ReaderState == Dev.Integration.HFReader.Constants.ReaderState.Open;
                                    break;
                                }
                            case "card_reader_m1_inventory":
                                {
                                    var tagInfo = _viewModel.CardReader.M1Inventory( );
                                    msg.Data["uid"] = tagInfo.UID;
                                    break;
                                }
                            case "card_reader_m1_read_block":
                                {
                                    msg.Data.TryGetValue( "no", out string no );    // 绝对块号. 范围: 0~63

                                    var blockInfo = _viewModel.CardReader.M1ReadBlock( block: no.ToIntOrDefault( defaultValue: 0 ) );
                                    msg.Data["uid"] = blockInfo.UID;
                                    msg.Data["no"] = blockInfo.BlockNo;
                                    msg.Data["data"] = blockInfo.BlockData;
                                    break;
                                }
                            case "card_reader_icr_inventory":
                                {
                                    var tagInfo = _viewModel.CardReader.ICRInventory( );
                                    msg.Data["uid"] = tagInfo.UID;
                                    break;
                                }
                            #endregion

                            case "test":
                                {
                                    break;
                                }
                            default: throw new Exception( $"无效的指令: {msg.Cmd}" );
                        }
                    }
                    catch ( Exception ex )
                    {
                        msg.Status = System.Net.HttpStatusCode.BadRequest;
                        msg.Error = ex.Message;
                    }

                    // 响应客户端消息
                    var message = msg.ToJson( );
                    socket.Send( message );
                    _logger.Debug( $"ws 响应客户端消息: {message}" );
                };
            } );


            _logger.Info( $"注册成功. {_server.Location}" );
            await Task.CompletedTask;
        }

        public async Task StopAsync( CancellationToken cancellationToken )
        {
            _server.Dispose( );

            _logger.Info( $"注销成功" );
            await Task.CompletedTask;
        }
    }
}
